/* src/interfaces/ecpg/include/ecpg-pthread-win32.h */
/*
 * pthread mapping macros for win32 native thread implementation
 */
#ifndef _ECPG_PTHREAD_WIN32_H
#define _ECPG_PTHREAD_WIN32_H

#ifdef ENABLE_THREAD_SAFETY

#ifndef WIN32

#include <pthread.h>
#else

typedef struct pthread_mutex_t {
    HANDLE handle;
    LONG initlock;
} pthread_mutex_t;

typedef DWORD pthread_key_t;
typedef bool pthread_once_t;

#define PTHREAD_MUTEX_INITIALIZER \
    {                             \
        NULL, 0                   \
    }
#define PTHREAD_ONCE_INIT false

void win32_pthread_mutex(volatile pthread_mutex_t* mutex);
void win32_pthread_once(volatile pthread_once_t* once, void (*fn)(void));

#define pthread_mutex_lock(mutex)                       \
    do {                                                \
        if ((mutex)->handle == NULL)                    \
            win32_pthread_mutex((mutex));               \
        WaitForSingleObject((mutex)->handle, INFINITE); \
    } while (0)

#define pthread_mutex_unlock(mutex) ReleaseMutex((mutex)->handle)

#define pthread_getspecific(key) TlsGetValue((key))

#define pthread_setspecific(key, value) TlsSetValue((key), (value))

/* FIXME: destructor is never called in Win32. */
#define pthread_key_create(key, destructor) \
    do {                                    \
        *(key) = TlsAlloc();                \
        ((void)(destructor));               \
    } while (0)

#define pthread_once(once, fn)                \
    do {                                      \
        if (!*(once))                         \
            win32_pthread_once((once), (fn)); \
    } while (0)
#endif /* WIN32 */
#endif /* ENABLE_THREAD_SAFETY */

#endif /* _ECPG_PTHREAD_WIN32_H */
